
#include "peer_client_process.h"
#include "stun_message.h"
#include "turn_client_main/file_operation.h"
#include "udp_client.h"
#include <arpa/inet.h>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <netinet/in.h>
#include <sys/socket.h>


void PeerProcessBindResponse(LoopEvent * loop_event, UdpClient * client, StunMessage & message, PeerClientInformation & information)
{
	auto attr_map = message.m_attr_map;

	auto xor_addr_iter = attr_map.find(EmXorMappedAddress);
	if (xor_addr_iter != attr_map.end() && xor_addr_iter->second)
	{
		auto xor_addr = (AttrXorMappedAddress*)xor_addr_iter->second.get();
		std::string ip = xor_addr->DecoderAddr();
		uint16_t    port = xor_addr->DecoderPort();

		information.m_srfix_ip = ip;
		information.m_srfix_port = port;
		// candidate
		printf("peer srfix ip : %s\tport : %d.\n", ip.c_str(), port);
		// check allocate 
		// TestAllocate(loop_event, information);
	}
	else 
	{
		printf("no found EmXorMappedAddress attr information.\n");
	}
}

void ProcessDataFromRelayServer(LoopEvent *loop_event, UdpClient *client, PeerClientInformation &information, UdpBufferPacket * packet)
{
	// echo data to relay server
	// client->DoSendMsg(data, length);
	// client->DoSendMsg(packet->sai, packet->sai_len, packet->buffer->Data(), packet->buffer->Length());
	// save data to file
	uint32_t index = 0;
	memcpy(&index, packet->buffer->Data(),sizeof(index));
	if (index == 0)
	{
		information.m_lost_packet.m_order_packet_index = index;
		information.m_lost_packet.m_packet_index_set.insert(index);
		loop_event->PushAfterTask(20 * 1000, [&information](){


			printf("lost packet index : ");
			for (auto & index : information.m_lost_packet.m_lost_packet_index_vec)
			{
				printf("%d(%x) ", index, index);
			}
			printf("\n");

		});
	}
	else if (index != (information.m_lost_packet.m_order_packet_index + 1))
	{
		uint32_t lost_count = (index - information.m_lost_packet.m_order_packet_index - 1);
		for (uint32_t i = 1; i <= lost_count; i++)
		{
			uint16_t lost_index = information.m_lost_packet.m_order_packet_index + i;
			information.m_lost_packet.m_lost_packet_index_vec.push_back(lost_index);
		}
		information.m_lost_packet.m_order_packet_index = index;
	}
	else
	{
		information.m_lost_packet.m_order_packet_index++;
	}
	SaveFileContent(information.m_file_operation, packet->buffer->Data() + sizeof(index), packet->buffer->Length() - sizeof(index));
	printf("------------------> recv data packet index : %d  and index : %d and data length : %d.\n", information.m_file_operation.m_packet_index++, index, packet->buffer->Length());
}

void TestAllocate(LoopEvent * loop_event,PeerClientInformation & information)
{
	if (!information.m_ip.empty() && information.m_port != 0)
	{
		printf("[%s][%s:%d].\n", __func__, information.m_ip.c_str(), information.m_port);
		if (information.m_relay_client)
		{
			loop_event->PushTask([&information](){

				StunMessage message;
			    message.SetMsgType(EmBindRequest);
			    message.m_transaction_id = message.ProducerTransactionId();
			    message.m_magic_cookie   = magic_cookie;

			    WriteBuffer buffer;
			    message.ComposeStunPacket(buffer);
			    struct sockaddr_in sai;
			    sai.sin_family = AF_INET;
			    sai.sin_port   = htons(information.m_port);
			    inet_pton(AF_INET, information.m_ip.c_str(), &sai.sin_addr.s_addr);
			    information.m_relay_client->DoSendMsg((struct sockaddr*)&sai, sizeof(sai), buffer.Data(), buffer.Length());
			});
		}
	}
	loop_event->PushAfterTask(8 * 1000, [loop_event, &information](){

		TestAllocate(loop_event, information);
	});
}